package com.example.service.Impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.enums.KeyEnum;
import com.example.common.enums.ResultCodeEnum;
import com.example.common.exception.CustomException;
import com.example.context.BaseContext;
import com.example.mapper.MenuMapper;
import com.example.pojo.entity.*;
import com.example.pojo.utils.RouteMeta;
import com.example.service.MenuService;
import com.example.service.MetaService;
import com.example.utils.TransUtils;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 菜单管理Service实现类
 *
 * @author ding
 * @since 2024/7/2
 */
@Service
@Slf4j
@CacheConfig(cacheNames = "menu", keyGenerator = "keyGenerator")
public class MenuServiceImp extends ServiceImpl<MenuMapper, RouteItem> implements MenuService {

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private MetaService metaService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 获取所有的菜单
     */
    @Transactional(readOnly = true)
    @Cacheable
    public List<RouteItem> getAllMenu() {
//        String menuString = (String) redisTemplate.opsForValue().get(KeyEnum.MENU_USE);

        //当前登录用户的id
        Integer currentId = BaseContext.getCurrentId().intValue();
        MPJLambdaWrapper<RouteItem> mpjLambdaWrapper = new MPJLambdaWrapper<>();
        mpjLambdaWrapper
                .selectAll(RouteItem.class)
                .innerJoin(RoleAndMenu.class, RoleAndMenu::getMenuId, RouteItem::getId)
                .innerJoin(Role.class, Role::getId, RoleAndMenu::getRoleId)
                .innerJoin(UserAndRole.class, UserAndRole::getRoleId, Role::getId)
                .innerJoin(Admin.class, Admin::getId, UserAndRole::getUserId)
                .eq(Admin::getId, currentId)
                .eq(RouteItem::getLevel, 1)
                .eq(RouteItem::getStatus, 0)
                .eq(RouteItem::getIsDeleted, 0)
                .orderByAsc(RouteItem::getOrderNo);
        //获取当年登录用户对应角色的
        List<RouteItem> routeItems = menuMapper.selectList(mpjLambdaWrapper);

            //获取所有一节菜单
//        List<RouteItem> routeItems = menuMapper.selectList(new LambdaQueryWrapper<RouteItem>()
//                .eq(RouteItem::getLevel, 1)
//                .eq(RouteItem::getStatus, 0)
//                .eq(RouteItem::getIsDeleted, 0)
//                .orderByAsc(RouteItem::getOrderNo));

        for (RouteItem routeItem : routeItems) {
            //为每个父菜单设置样式
            RouteMeta parentMeat = metaService.getOne(new LambdaQueryWrapper<RouteMeta>().eq(RouteMeta::getMenuId, routeItem.getId()));
            if (ObjectUtil.isNotEmpty(parentMeat.getIsShow()) && parentMeat.getIsShow() == 1) {
                parentMeat.setHideMenu(true);
            }
            if (ObjectUtil.isNotEmpty(parentMeat.getChildrenMenu()) && parentMeat.getChildrenMenu() == 1){
                parentMeat.setHideChildrenInMenu(true);
            }
            routeItem.setMeta(parentMeat);

//            //为父菜单设置子菜单
//            List<RouteItem> childMenu = menuMapper.selectList(new LambdaQueryWrapper<RouteItem>()
//                    .eq(RouteItem::getIsDeleted, 0)
//                    .eq(RouteItem::getLevel, 2));
            MPJLambdaWrapper<RouteItem> childMpjLambdaWrapper = new MPJLambdaWrapper<>();
            childMpjLambdaWrapper
                    .selectAll(RouteItem.class)
                    .innerJoin(RoleAndMenu.class, RoleAndMenu::getMenuId, RouteItem::getId)
                    .innerJoin(Role.class, Role::getId, RoleAndMenu::getRoleId)
                    .innerJoin(UserAndRole.class, UserAndRole::getRoleId, Role::getId)
                    .innerJoin(Admin.class, Admin::getId, UserAndRole::getUserId)
                    .eq(Admin::getId, currentId)
                    .eq(RouteItem::getLevel, 2)
                    .eq(RouteItem::getStatus, 0)
                    .eq(RouteItem::getIsDeleted, 0)
                    .eq(RouteItem::getParentMenu, routeItem.getId())
                    .orderByAsc(RouteItem::getOrderNo);
            List<RouteItem> childMenu = menuMapper.selectList(childMpjLambdaWrapper);


            Integer num = 0;
            List<Integer> childIds = new ArrayList<>();
            for (RouteItem menu : childMenu) {
                if (routeItem.getSerial().equals(menu.getSerial().split("-")[0])){
                    num++;
                    childIds.add(menu.getId());
                }
            }
            RouteItem[] childs = new RouteItem[num];
            for (int i = 0; i < childs.length; i++) {
                RouteItem m = menuMapper.selectById(childIds.get(i));
                //为每个子菜单设置样式
                RouteMeta meta = metaService.getOne(new LambdaQueryWrapper<RouteMeta>()
                        .eq(RouteMeta::getMenuId, m.getId()));
                //菜单是否隐藏 默认不隐藏
                if (ObjectUtil.isNotEmpty(meta.getIsShow()) && meta.getIsShow() == 1) {
                    meta.setHideMenu(true);
                }
                //菜单是否隐藏子菜单 默认不隐藏子菜单
                if (ObjectUtil.isNotEmpty(meta.getChildrenMenu()) && meta.getChildrenMenu() == 1){
                    meta.setHideChildrenInMenu(true);
                }
                //菜单是否开启缓存 默认为0 不缓存
                if (ObjectUtil.isNotEmpty(meta.getIsKeep()) && meta.getIsKeep() == 1){
                    meta.setIgnoreKeepAlive(true);
                }
                m.setMeta(meta);
                childs[i] = m;
            }
            routeItem.setChildren(childs);
        }

//            String jsonString = JSON.toJSONString(routeItems);
//            redisTemplate.opsForValue().set(KeyEnum.MENU_USE, jsonString);
//            redisTemplate.expire(KeyEnum.MENU_USE, 4, TimeUnit.HOURS);

        return routeItems;

    }

    /**
     * 获取传递来的菜单信息
     */
    public void sumbitMenu(RouteItem routeItem) {
        RouteItem dbMenu = menuMapper.selectOne(new LambdaQueryWrapper<RouteItem>().eq(RouteItem::getId, routeItem.getId()));

        //无论是新增菜单还是更新菜单，都将Redis中的菜单数据清空
//        redisTemplate.delete(KeyEnum.MENU_USE);
        redisTemplate.delete(KeyEnum.MENU_MANAGER);

        if (ObjectUtil.isNotEmpty(dbMenu)) {
            updateMeny(routeItem);
        } else {
            addMenu(routeItem);
        }
    }

    /**
     * 新增新菜单信息
     */
    public void addMenu(RouteItem routeItem){
        log.info("新增菜单信息:{}", routeItem);

        String name = getEn(routeItem.getMenuName());
        routeItem.setName(name);

        //根据菜单等级不同，菜单设置不同的component路径
        if (ObjectUtil.isEmpty(routeItem.getParentMenu())){
            //如果新增菜单没有设置父菜单，则为一级菜单

            //为菜单设置菜单等级
            routeItem.setLevel(1);
            //获取全部的一级菜单个数，设置父菜单标识
            List<RouteItem> menuListByLevel = getMenuListByLevel(1);
            routeItem.setSerial("" + (menuListByLevel.size() + 1));

            //一级菜单url需要拼接 /
            routeItem.setPath("/" + name.replace(" ", "").toLowerCase());

        }else {
            //如果有父菜单信息，则默认为二级菜单
            routeItem.setLevel(2);
            //为二级菜单设置父菜单标识
            RouteItem parentMenu = getParentMenu(routeItem.getParentMenu());
            routeItem.setSerial(parentMenu.getSerial() + "-" + (getBroMenuListByParId(routeItem.getParentMenu()).size()+1));

            //若为二级菜单 则将菜单名称翻译为英文，再与父菜单的路径进行拼接
            //设置路径
            //若为二级菜单，则设置的url不需要增加 /, 父菜单会自动为其拼接一个 /
            routeItem.setPath(name.replace(" ", "").toLowerCase());

        }

        //设置逻辑删除字段和乐观锁字段
        routeItem.setIsDeleted(0);
        routeItem.setVersion(0);

        menuMapper.insert(routeItem);

        //设置菜单样式
        RouteMeta routeMeta = new RouteMeta();
        //设置菜单样式关联菜单ID
        routeMeta.setMenuId(routeItem.getId());
        //设置菜单图标
        if (routeItem.getIcon().length() > 3) {
            routeMeta.setIcon(routeItem.getIcon());
        }
        //设置菜单名称
        routeMeta.setTitle(routeItem.getMenuName());
        //设置排序
        routeMeta.setOrderNo(routeItem.getOrderNo());
        //设置菜单是否显示  0：菜单显示 1：菜单不显示  管理meta中的属性 hideMenu：是否隐藏菜单，0：不隐藏菜单；1：隐藏菜单
        routeMeta.setIsShow(Integer.valueOf(routeItem.getShow()));
        //设置菜单是否缓存 0：菜单进行缓存 1：菜单不缓存  对应meta中的属性 ignoreKeepAlive 0：不缓存 1：缓存
        if (ObjectUtil.isNotEmpty(routeItem.getKeepalive())){
            routeMeta.setIsKeep(Integer.valueOf(routeItem.getKeepalive()));
        }
        routeMeta.setIsDeleted(0);
        routeMeta.setVersion(0);
        metaService.addMeta(routeMeta);
    }

    /**
     * 修改菜单信息
     */
    public void updateMeny(RouteItem routeItem) {
        RouteItem dbMenu = menuMapper.selectOne(new LambdaQueryWrapper<RouteItem>().eq(RouteItem::getId, routeItem.getId()));
        routeItem.setLevel(dbMenu.getLevel());
        routeItem.setSerial(dbMenu.getSerial());
        routeItem.setId(dbMenu.getId());
        RouteMeta meta = metaService.getOne(new LambdaQueryWrapper<RouteMeta>().eq(RouteMeta::getMenuId, routeItem.getId()));
        //是否修改菜单的父菜单
        if (ObjectUtil.isNotEmpty(routeItem.getParentMenu())) {
            if(routeItem.getLevel() != 1){
                //获取当前菜单的老父菜单的，便于在为当前菜单赋予新父菜单时，
                // 为之前老父菜单的子菜单重复赋予父菜单索引Serial
                String oldParentSerial = routeItem.getSerial().split("-")[0];
                RouteItem oldParentMenu = menuMapper.selectOne(new LambdaQueryWrapper<RouteItem>().eq(RouteItem::getSerial, oldParentSerial));

                //子菜单与父菜单的id，通过
                Integer parentId = routeItem.getParentMenu();
                List<RouteItem> broList = menuMapper.selectList(new LambdaQueryWrapper<RouteItem>().eq(RouteItem::getParentMenu, parentId));
                routeItem.setSerial(menuMapper.selectById(parentId).getSerial() + "-" + (broList.size()+1));
                routeItem.setParentMenu(parentId);

                String newTran = getEn(routeItem.getMenuName());
                //设置新的菜单名称
                routeItem.setName(TransUtils.getMethodName(newTran));
                //设置新的path
                routeItem.setPath(newTran.replace(" ","").toLowerCase());

                updateById(routeItem);

                //获取到新菜单之前的兄弟菜单, 为其设计新的父菜单标识
                List<RouteItem> oldBroList = getBroMenuListByParId(oldParentMenu.getId());
                int count = 1;
                for (RouteItem item : oldBroList) {
                    item.setSerial(oldParentSerial + "-" + count++);
                    updateById(item);
                }
            }else {
                throw new CustomException(ResultCodeEnum.MENU_NOT_PATENT);
            }
        }else {
            //更新一级菜单
            //设置新的菜单名称
            String newTran = getEn(routeItem.getMenuName());
            routeItem.setName(TransUtils.getMethodName(newTran));
            //设置新的path
            routeItem.setPath("/" + newTran.replace(" ", "").toLowerCase());

            updateById(routeItem);
        }
        //更新菜单的图标
        if (routeItem.getIcon().length() > 3) {
            meta.setIcon(routeItem.getIcon());
        }
        //菜单显示更新
        if ("1".equals(routeItem.getShow())) {
            //菜单不显示
            meta.setIsShow(1);
        }else if ("0".equals(routeItem.getShow())){
            //菜单显示
            meta.setIsShow(0);
        }
        //是否开启缓存
        if ("1".equals(routeItem.getKeepalive())){
            //开启缓存
            meta.setIsKeep(1);
        }else {
            //不开启缓存
            meta.setIsKeep(0);
        }
        //为菜单设置新的名称
        meta.setTitle(routeItem.getMenuName());
        metaService.updateById(meta);
    }

    /**
     * 根据id删除菜单信息
     */
    public void deleteMenu(Integer id) {
        RouteItem routeItem = menuMapper.selectById(id);
        if (routeItem.getLevel() == 1){
            //如果为一级菜单，则需要将其子菜单一并删除
            List<RouteItem> childMenu = menuMapper.selectList(new LambdaQueryWrapper<RouteItem>()
                    .eq(RouteItem::getParentMenu, routeItem.getId()));
            for (RouteItem menu : childMenu) {
                menu.setIsDeleted(1);
                updateById(menu);
            }
            routeItem.setIsDeleted(1);
            updateById(routeItem);
        }else {
            //为二级菜单
            routeItem.setIsDeleted(1);
            updateById(routeItem);
        }
    }

    //根据菜单等级获取对应的菜单列表
    public List<RouteItem> getMenuListByLevel(Integer level) {
        return menuMapper.selectList(new LambdaQueryWrapper<RouteItem>().eq(RouteItem::getLevel, level));
    }

    //根据父菜单id获取对应的兄弟菜单列表
    public List<RouteItem> getBroMenuListByParId(Integer parentId) {
        return menuMapper.selectList(new LambdaQueryWrapper<RouteItem>().eq(RouteItem::getParentMenu, parentId));
    }

    //根据父菜单ID获取对应的父菜单信息
    public RouteItem getParentMenu(Integer parentId) {
        return menuMapper.selectOne(new LambdaQueryWrapper<RouteItem>().eq(RouteItem::getId, parentId));
    }

    //将中文字符串翻译为英文字符串
    public String getEn(String cn) {
        String transToEn = TransUtils.TransToEn(cn);
        String newTran = transToEn.split(",")[0];
        newTran = newTran.substring(newTran.indexOf(":")+2, newTran.lastIndexOf("\""));
        return newTran;
    }

}
